package server

import (
	"Bulb/data"
	"Bulb/packet"
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

const MaxConnection = 128
const MaxSession = 1024
const Port = ":80"

type Message struct {
	Uid     int
	Content []byte
}

// 存储所有活动连接的结构体
type Hub struct {
	clients    map[int]*websocket.Conn
	broadcast  chan []byte
	sendQueue  chan Message
	unregister chan int
	mutex      sync.Mutex
}

var hub = Hub{
	clients:    make(map[int]*websocket.Conn, MaxConnection),
	sendQueue:  make(chan Message, 16),
	broadcast:  make(chan []byte, 5),
	unregister: make(chan int),
}

func Start() {
	InitPublic()
	InitAdmin()
	go handleMessages()
	log.Println("服务器在 ", Port, " 端口上运行")
	err := http.ListenAndServe(Port, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
func SendToClient(uid int, msg []byte) {
	if conn := hub.clients[uid]; conn != nil {
		hub.sendQueue <- Message{uid, msg}
	}
}

func SendToAdmin(msg []byte) {
	SendToClient(0, msg)
}

func BroadcastMessage(msg []byte) {
	hub.broadcast <- msg
}

func trySendMessage(uid int, conn *websocket.Conn, msg []byte) { //此函数只会在handleMessages中被调用，且已加锁
	if conn == nil {
		log.Println("无法向离线用户发信：", uid)
		delete(hub.clients, uid)
		//hub.clients[uid] = nil //应该是不必要的
		return
	}
	err := conn.WriteMessage(websocket.TextMessage, msg)
	if err != nil {
		log.Println("写消息失败:", err)
		conn.Close()
		delete(hub.clients, uid)
		//hub.clients[uid] = nil
	}
}

func handleMessages() {
	for {
		select {
		case uid := <-hub.unregister:
			hub.mutex.Lock()
			fmt.Println("Seems lost ", uid)
			delete(hub.clients, uid)
			//hub.clients[uid] = nil
			hub.mutex.Unlock()
			go func() { //如果两秒内没有重连则删除数据
				time.Sleep(time.Second * 2)
				if hub.clients[uid] == nil {
					data.RemoveUser(uid)
					BroadcastMessage(packet.EncodeServerPacket(packet.NewOnlineCountPacket(data.OnlineCount())))
					SendToAdmin(packet.EncodeServerPacket(packet.NewUserDataInitPacket(data.GetAllUserData())))
					fmt.Println("Lost ", uid)
				}
			}()
		case message := <-hub.broadcast:
			hub.mutex.Lock()
			for uid, client := range hub.clients {
				if client == nil {
					continue
				}
				trySendMessage(uid, client, message)
			}
			hub.mutex.Unlock()
		case message := <-hub.sendQueue:
			trySendMessage(message.Uid, hub.clients[message.Uid], message.Content)
		}
	}
}
